CSU 1720 How to Get 2^n(trie上贪心、高精度)

题意:

$给定N\le 10^5个数,1\le A_i\le 10^{30}(2^{100}>10^{30})$
$求A_i+A_j=2^x的(i, j)对数$

分析:

$先把大整数转换成二进制,然后从低位到高位插到trie里$
$对于每个数A_i,先找到1个A_j,使得A_i+A_j为最小的那个2^x,从trie上找到A_j$
$对于之后比它大的2^y,A_j’的取值是A_j从x这个二进制位起都是1,trie累加之后的即可$
$感觉不是很好写,时间复杂度O(nb),b=100$

代码:

//
//  Created by TaoSama on 2016-04-24
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <bitset>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const int B = 101;

int n;

struct Type {
    int n;
    bitset<B> b;
    Type() {
        n = 0;
        b.reset();
    }
};

Type a[N];

void toBinary(Type& a, char* b) {
    a = Type();
    int n = strlen(b);
    for(int i = 0; i < n; ++i) b[i] -= '0';
    reverse(b, b + n);

    int cnt = 0; --n;
    while(~n) {  //use b[0], u fucking zz
        a.b[a.n++] = b[0] & 1; //mod
        int mod = 0;
        for(int i = n; ~i; --i) { //divide
            mod = mod * 10 + b[i];
            b[i] = mod >> 1;
            mod &= 1;
        }
        if(!b[n]) --n;
    }
}

Type subtract(Type& a, Type& b) {
    Type ret;
    bool lent = false;
    for(int i = 0; i < B; ++i) {
        int x = a.b[i];
        if(lent) {
            x -= 1;
            if(x < 0) x += 2;
            else lent = false;
        }
        x -= b.b[i];
        if(x < 0) {
            x += 2;
            lent = true;
        }
        ret.b[i] = x;
    }
    return ret;
}

char b[50];

int getBitLength(Type& b) {
    int bits = 0;
    for(int j = B; j; --j) {
        if(b.b[j - 1]) {
            bits = j;
            break;
        }
    }
    return bits;
}

struct Trie {
    static const int M = B * 1e5 + 10, S = 2;
    int nxt[M][S], val[M];
    int root, sz;
    int newNode() {
        val[sz] = 0;
        memset(nxt[sz], 0, sizeof nxt[sz]);
        return sz++;
    }
    void init() {
        sz = 0; newNode();
        root = newNode();
    }
    void update(Type& b, int d) {
        int u = root;
        for(int i = 0; i < b.n; ++i) {
            int c = b.b[i], &v = nxt[u][c];
            if(!v) v = newNode();
            u = v;
        }
        val[u] += d;
    }
    int query(Type& b, int bits) {
        int u = root;
        int ret = 0, n = getBitLength(b);
        for(int i = 0; i < bits; ++i) {
            int c = b.b[i];
            u = nxt[u][c];
            if(i == n - 1) ret += val[u];
        }
        for(int i = bits; i < B; ++i) {
            u = nxt[u][1];
            ret += val[u];
        }
        return ret;
    }
} trie;

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);

        trie.init();
        for(int i = 1; i <= n; ++i) {
            scanf("%s", b);
            toBinary(a[i], b);
            trie.update(a[i], 1);
        }

        long long ans = 0;
        for(int i = 1; i <= n; ++i) {
            trie.update(a[i], -1);

            int bits = a[i].n;
            Type b; b.b[bits] = 1;
            Type c = subtract(b, a[i]);
            ans += trie.query(c, bits);

            trie.update(a[i], 1);
        }

        printf("%lld\n", ans >> 1);
    }
    return 0;
}